(function() {
	panda.proxy = function(name) {
		return { __noSuchMethod__: delegate };

		function delegate(method, args) {
			var target = eval(name);
			var expr = name + "." + method;
			var proxies = panda.map(proxy, checkProxy);
			proxies.sort(sort);

			var obj = { __noSuchMethod__: delegate };
			obj[method] = target[method];

			panda.each(proxies, function(p){
				p.methods.sort(sort);
				panda.each(p.methods, eachMethod);
			});

			return obj[method].apply(obj, args);

			function checkProxy(p) {
				var methods = panda.grep(p, function(m){
					return m.expr && m.expr.test(expr);
				});

				if (!methods.length) { return; } 

				return {
					priority: p.priority,
					methods: methods
				};
			}

			function eachMethod(m) {
				var old = obj;
				obj = { __noSuchMethod__: delegate };
				obj[method] = function() {
					return m.func.call(old, name, method, arguments);
				}
			}

			function sort(a, b) {
				return a.priority - b.priority;
			}
		}
	};
}());
